#include "SypEngine.h"

#ifdef CHECKMEM
#include "mmgr.h"
#endif
#define FILEVERSION 0.13f
namespace Syp
{
	IndexedMesh*	IndexedMesh::createIndexedMesh(const String& filename,ModelType t)
	{
		return new IndexedMesh(filename,t);
	}
	void IndexedMesh::destroyIndexedMesh(IndexedMesh* mesh)
	{
		delete mesh;
	}

	PShortArray& IndexedMesh::getIndexArrayRef()
	{
		return index;
	}

	IndexedMesh::IndexedMesh(const String& filename,ModelType t):BaseMesh(filename),skeleton(0)
	{
		type = t;
		hasSkin = false;
		//Generate VBO if it is static
		Renderer::getRenderer().addMesh(this);
		currAnimTrans = -1.0f;
	}

	//IMPORTANT - A MILLION BRAIN CELLS DIED IN DEBUGGING THIS. THIS INFORMATION EXPLAINS IN DETAIL THE PROCESS OF DOING SKELETAL ANIMATION
	/*
	1) ALWAYS ALWAYS make a matrix for transformations after bone has reached identity.
	Previously i was using parents entire matrix transformation to calculate childs position which resulted in wrong results.

	Method:

	//Apply the transformations after the inverse and store it as forward. Only to be used after bone has reached back to identity after using inverse matrix.
	Math::multMat(b.invB,rotMatrix,b.forward);

	//Move bone back to where it was after inverse
	Math::multMat(b.forward,b.inv, temp);

	//apply parents matrix after everything is done
	NOTE HERE, U apply PARENTS->FORWARD and not PARENTS->MAT.
	THIS IS THE REASON FOR A SEPERATE FORWARD MATRIX
	Math::multMat(b.ParentPtr->forward,temp,b.mat);

	*/

	Skeleton* IndexedMesh::getSkeleton()
	{
		return skeleton;
	}

	float IndexedMesh::getCurrAnimTrans()
	{
		return currAnimTrans;
	}

	PShortArray& IndexedMesh::getSkinIDRef()
	{
		return skinID;
	}

	std::vector<VertexWeightSet>& IndexedMesh::getVWeightsRef()
	{
		return VWeights;
	}

	FloatArray& IndexedMesh::getBakDataRef()
	{
		return bakData;
	}

	void IndexedMesh::setCurrAnimTrans(float currTime)
	{
		currAnimTrans = currTime;
	}

	void IndexedMesh::useSkeleton(Skeleton* sk)
	{
		assert(sk && "Null Pointer passed into function IndexedMesh::useSkeleton()");
		skeleton = sk;
		sk->addInstance();

	}

	void IndexedMesh::setBindPoseMatrix(float* mat)
	{
		for(int i=0;i<16;++i)
		{
			bindMat[i] = mat[i];
		}
	}

	void IndexedMesh::transformBone(Bone& b)
	{
		std::vector<KeyFrame>::iterator LowerKey;
		std::vector<KeyFrame>::iterator UpperKey;

		//This bone will now be transformed to this time. This is to reflect to all other bones whether or not this bone has undergone transformation yet.
		b.currTime = currAnimTrans;

		KeyFrame tk;
		tk.time = currAnimTrans;

		//we want the last element
		LowerKey = b.KFrame.end();
		--LowerKey;

		//If the time we need is more than the last key frame, use last keyframe
		// NOTE: This will only happen if all bones do not have the same lastKeyFrame
		if(currAnimTrans >= (LowerKey->time))
		{
			//We leave the bone at it's last keyframe
			//Give value to UpperKey and then negate to Lower
			UpperKey = LowerKey--;

		}
		else
		{
			//find the 2 keys surrounding this time
			LowerKey = std::upper_bound( b.KFrame.begin(),
				b.KFrame.end(),
				tk);
			UpperKey = LowerKey--;
		}
		//Orientation of bone after interpolation
		Quat FinalRot;
		Point3 FinalPos;
		//Time diff btwn 2 keyframes
		double timeDiff = UpperKey->time - LowerKey->time;
		//Interpolation between the 2 frames
		float interpolation = static_cast<float> ( (currAnimTrans - LowerKey->time) / timeDiff);
		//This will happen when the last keyframe of a bone is not the same as the last keyframe of other bones.
		if(interpolation > 1.0f)
		{
			interpolation = 1.0f;
		}
		//Calculate the Interpolated Quat
		Math::InterpolateQuat(LowerKey->Rot,UpperKey->Rot,FinalRot, interpolation);
		//Rotates mesh
		float rotMatrix[16];
		//Translates mesh
		float posMatrix[16];
		Math::IdentityMatrix(posMatrix);
		//Temporary
		float tempf[16];
		//float superSian[16];
		//Math::IdentityMatrix(superSian);


		//Get the rotation matrix
		Math::QuatToMatrix(FinalRot,rotMatrix);

		//Note:: Every forward matrix has all it's parents forwards conjugated.

		if(b.getParentPtr())
		{
			//Positional easy stuff
			Math::InterpolatePoint3(LowerKey->Pos,UpperKey->Pos,FinalPos, interpolation);
			posMatrix[12] = FinalPos.x;
			posMatrix[13] = FinalPos.y;
			posMatrix[14] = FinalPos.z;

			Bone* parent = (Bone*)(b.getParentPtr());
			//Move bone back after rotation
			Math::multMat(posMatrix,rotMatrix,tempf);
			//recursive
			if(parent->currTime != b.currTime)
			{
				transformBone(*parent);
			}
			//apply parents matrix after everything is done
			Math::multMat(parent->forward,tempf,b.forward);
			Math::multMat(b.forward, b.inv, b.getMatrix());

		}
		else
		{
			Math::InterpolatePoint3(LowerKey->Pos,UpperKey->Pos,FinalPos, interpolation);
			/*posMatrix[12] = FinalPos.x + b.invB[12];
			posMatrix[13] = FinalPos.y + b.invB[13];
			posMatrix[14] = FinalPos.z + b.invB[14];*/
			posMatrix[12] = FinalPos.x;
			posMatrix[13] = FinalPos.y;
			posMatrix[14] = FinalPos.z;
			//Straight away apply answer to forward
			Math::multMat(posMatrix,rotMatrix,b.forward);
			//Move bone back to where it was then apply forward
			Math::multMat(b.forward,b.inv, b.getMatrix());
			//apply everything after we transform mesh from object space to world space
			//Math::multMat(superSian,bindMat,b.mat);
		}


//		printf("CurrAnimTime %f LowerKey %f UpperKey %f Interpolation %f \n", currAnimTrans,(*LowerKey).time,(*UpperKey).time, interpolation );

	}

	float* IndexedMesh::getBindPoseMatrix()
	{
		return bindMat;
	}

	IndexedMesh::~IndexedMesh()
	{
		if(skeleton)
		{
			skeleton->removeInstance();
		}
		//remove mesh from gfx card
		removeFromVRAM();
	}

	void IndexedMesh::draw()
	{
		Renderer::getRenderer().drawIndexed(this);
	}

	void IndexedMesh::removeFromVRAM()
	{
		Renderer::getRenderer().removeMeshFromVRAM(this);
	}

	void IndexedMesh::updateMesh()
	{
		Renderer::getRenderer().updateMesh(this);
	}

	bool IndexedMesh::isSkinned()
	{
		return hasSkin;
	}

	void IndexedMesh::setHasSkin(bool gotSkin)
	{
		hasSkin = gotSkin;
	}

	void IndexedMesh::writeToFile(const String& name)
	{
		OutputStream bo;
		bo.open(name.c_str(), std::ios::binary);
		if( bo.is_open() )
		{
			float ver = FILEVERSION;
			PShort temp;
			PInt temp2;
			//File version
			bo.write( reinterpret_cast<char*>(&ver), sizeof(float));
			//Vertex Format
			temp = vertType;
			bo.write( reinterpret_cast<char*>(&temp), sizeof(temp));
			//Material filename size, followed by the filename
			temp = static_cast<PShort>(getMaterialName().size());
			bo.write( reinterpret_cast<char*>(&temp), sizeof(temp));
			bo.write(getMaterialName().c_str(),temp);
			//Radius of model
			float mRadius = getBoundingRadius();
			bo.write( reinterpret_cast<char*>(&mRadius), sizeof(mRadius));

			///Num of Vertices
			bo.write( reinterpret_cast<char*>(&numOfVertices),sizeof(numOfVertices) );
			///Num Of DrawCalls
			temp = static_cast<PShort>(drawCalls.size());
			bo.write( reinterpret_cast<char*>(&temp),sizeof(temp) );
			///Now all the drawCalls
			for(PInt i=0;i<temp;++i)
			{
				bo.write( reinterpret_cast<char*>(&drawCalls[i].materialID),sizeof(drawCalls[i].materialID));
				bo.write( reinterpret_cast<char*>(&drawCalls[i].smallest),sizeof(drawCalls[i].smallest));
				bo.write( reinterpret_cast<char*>(&drawCalls[i].largest),sizeof(drawCalls[i].largest));
				bo.write( reinterpret_cast<char*>(&drawCalls[i].count),sizeof(drawCalls[i].count));
				bo.write( reinterpret_cast<char*>(&drawCalls[i].offset),sizeof(drawCalls[i].offset));
			}
			///Even though the array holds PShorts, the values in the array are not unique therefore there can be more than sizeof(short) values in the array, so we use a PInt temp2
			///Num Of Indices size, followed by the indices
			temp2 = static_cast<PInt>(index.size());
			bo.write( reinterpret_cast<char*>(&temp2),sizeof(temp2) );
			bo.write( reinterpret_cast<char*>(&index[0]), temp2 * sizeof(PShort));
			///Finally the data size and the data itself
			temp2 = static_cast<PInt>(data.size());
			bo.write( reinterpret_cast<char*>(&temp2),sizeof(temp2) );
			bo.write( reinterpret_cast<char*>(&data[0]), temp2 * sizeof(float));
			//After data its on to skinning information
			bo.write( reinterpret_cast<char*>(&hasSkin), sizeof(bool));
			if(hasSkin)
			{
				//write the bindpose matrix
				bo.write( reinterpret_cast<char*>(bindMat), sizeof(float) * 16);
				temp = static_cast<PInt>(this->VWeights.size());
				//Number of VWeights
				bo.write( reinterpret_cast<char*>(&temp), sizeof(PInt));
				for(PInt i=0;i<temp;++i)
				{
                    //Number of Bones affected in this VWeight
					temp2 = static_cast<PInt>(VWeights[i].BoneID.size());
					bo.write( reinterpret_cast<char*>(&temp2), sizeof(PInt));
					for(PInt j=0;j<temp2;++j)
					{//for every Bone
						bo.write( reinterpret_cast<char*>(&VWeights[i].BoneID[j]), sizeof(PShort));//BoneID
						bo.write( reinterpret_cast<char*>(&VWeights[i].weight[j]), sizeof(float));//BoneID

					}


				}
				//Now its time for the SkinIDs which point vertices to the VWeights they are supposed to use
				PInt duh = static_cast<PInt>(skinID.size());
				std::cout<<"\n Attempting to write "<<duh<<" skinIDs.\n";

				bo.write( reinterpret_cast<char*>(&duh), sizeof(duh));
				for(PInt i=0;i<duh;++i)
				{
					bo.write(reinterpret_cast<char*>(&skinID[i]),sizeof(PShort));
				}

			}




		}
		else
		{
			ErrorLogger::getLogger()<<"Error writing mesh to file : "<<name<<std::endl;
		}

		bo.close();
	}

	IndexedMesh* IndexedMesh::loadFromFile(const String& fileName,bool autoUpdateMesh)
	{
		IndexedMesh* bm = static_cast<IndexedMesh*>(ResourceManager::getResourceManager().isResourceLoaded(fileName));
		if(bm)
		{
			return bm;
		}

		float temp;
		PShort tempPS;
		PInt temp2;
		int offset = 0;
		char chars[300];
		String str;

		IndexedMesh* sm = new IndexedMesh(fileName,STATIC);
		InputStream fin;
		fin.open(fileName.c_str(),std::ios::binary);
		//File Version
		fin.read(reinterpret_cast<char*>(&temp),sizeof(float));
		std::cout<<"\n File version is : "<<temp<<"\n";
		if(temp != FILEVERSION)
		{
			std::cout<<"\n File version of sypm file is outdated, please re-export file with latest Converter.This version of Syp requires files to be of version "<<FILEVERSION<<"\n";
			assert(0 && "File version of sypm file is outdated, please re-export file with latest Converter");

		}

		VertexType vt = VNT;
		fin.read(reinterpret_cast<char*>(&tempPS),sizeof(tempPS));
		switch(tempPS)
		{
		case 1:
			vt = VNT;
			offset = 8;
			break;
		case 2:
			vt = VT;
			offset = 5;
			break;
		case 3:
            vt = VN;
			offset = 6;
			break;
		case 4:
			vt = VC3;
			offset = 6;
			break;
		case 5:
			vt = VC4;
			offset = 7;
			break;
		case 6:
			vt = VC3T;
			offset = 8;
			break;
		case 7:
			vt = VC4T;
			offset = 9;
			break;
		default:
			assert(false && "WTF ARE YOU LOADING? Invalid vertextype");
			break;
		}
		sm->setVertexType(vt);
		//Material filename size
		fin.read(reinterpret_cast<char*>(&tempPS),sizeof(tempPS));
		fin.read(chars,tempPS);
		str.insert(0,chars,tempPS);
		std::cout<<"Material Filename : "<<str<<"\n";

		//Set material
		sm->setDefaultMaterial(str);
		//Model Radius
		float mRadius = 0.0f;
		fin.read( reinterpret_cast<char*>(&mRadius), sizeof(mRadius));
		sm->setBoundingRadius(mRadius);
		//Read in numVertices
		fin.read(reinterpret_cast<char*>(&sm->numOfVertices),sizeof(sm->numOfVertices));
		std::cout<<"Mesh has "<<sm->numOfVertices<<" vertices\n";
		fin.read(reinterpret_cast<char*>(&tempPS),sizeof(tempPS));
		std::cout<<"Mesh has "<<tempPS<<" drawcalls.\n";
		///Now all the drawCalls
		for(PInt i=0;i<tempPS;++i)
		{
			IndexBlock ib;
			fin.read( reinterpret_cast<char*>(&ib.materialID),sizeof(ib.materialID));
			fin.read( reinterpret_cast<char*>(&ib.smallest),sizeof(ib.smallest));
			fin.read( reinterpret_cast<char*>(&ib.largest),sizeof(ib.largest));
			fin.read( reinterpret_cast<char*>(&ib.count),sizeof(ib.count));
			fin.read( reinterpret_cast<char*>(&ib.offset),sizeof(ib.offset));
			sm->drawCalls.push_back(ib);
		}
		//Read in Num of indices, followed by the indices
		fin.read( reinterpret_cast<char*>(&temp2),sizeof(temp2) );
		sm->index.resize(temp2);
		fin.read( reinterpret_cast<char*>(&sm->index[0]), temp2 * sizeof(PShort));

		///Finally the data size and the data itself
		fin.read( reinterpret_cast<char*>(&temp2),sizeof(temp2) );
		sm->data.resize(temp2);
		fin.read( reinterpret_cast<char*>(&sm->data[0]), temp2 * sizeof(float));

		//After data its on to skinning information
		fin.read( reinterpret_cast<char*>(&sm->hasSkin), sizeof(bool));
		if(sm->hasSkin)
		{
			float tempMat[16];
			//write the bindpose matrix
			fin.read( reinterpret_cast<char*>(tempMat), sizeof(float) * 16);
			//TESTING WITHOUT BINDPOSE
			//Math::IdentityMatrix(tempMat);
			sm->setBindPoseMatrix(tempMat);
			sm->bakData.resize( sm->data.size(), 0 );
			//std::cout<<"Orig Data : "<<sm->data[ sm->data.size() - 4]<<"\n";
	//		//Copy it
			//std::copy( sm->data.begin(),sm->data.end(),sm->bakData.begin() );
			//We apply the bindpose matrix to the vertices/normals in bakData
			for(size_t i=0;i<sm->data.size(); i += offset)
			{
				Math::MultVectorByMatrix(
					//Bone [  BoneID from VWeights used by this vertex     ]
					//Use backupdata for original
					//Use the weight for this bone
					//Store in mesh
					tempMat,
					//m->getBindPoseMatrix(),
					&sm->getDataRef()[i],
					1.0f,
					&sm->getBakDataRef()[i]);

				//Normals
				Math::MultNormalByMatrix(
					tempMat,
					//m->getBindPoseMatrix(),
					&sm->getDataRef()[i + 3],
					1.0f,
					&sm->getBakDataRef()[i + 3]);
				if( vt == Syp::VNT)
				{
					sm->getBakDataRef()[i + 6] = sm->getDataRef()[i + 6];
					sm->getBakDataRef()[i + 7] = sm->getDataRef()[i + 7];

				}
			}
			std::copy( sm->getBakDataRef().begin(), sm->getBakDataRef().end(), sm->getDataRef().begin() );

			//std::cout<<"Bak Data : "<<sm->bakData[ sm->data.size() - 4]<<"\n";
			PInt temp7;
			//Number of VWeights
			fin.read( reinterpret_cast<char*>(&temp7), sizeof(PInt));
			for(PInt i=0;i<temp7;++i)
			{
				Syp::VertexWeightSet vw;
				//Number of finnes affected in this VWeight

				fin.read( reinterpret_cast<char*>(&temp2), sizeof(PInt));
				for(PInt j=0;j<temp2;++j)
				{//for every finne
					PShort t1;
					float f1;
					fin.read( reinterpret_cast<char*>(&t1), sizeof(PShort));//finneID
					fin.read( reinterpret_cast<char*>(&f1), sizeof(float));//WEight
					vw.BoneID.push_back(t1);
					vw.weight.push_back(f1);

				}

				sm->getVWeightsRef().push_back(vw);
			}

			PInt duh;
			PShort val;
			fin.read( reinterpret_cast<char*>(&duh), sizeof(duh));
			sm->skinID.reserve(duh);
			for(PInt i=0;i<duh;++i)
			{
				fin.read(reinterpret_cast<char*>(&val),sizeof(PShort));
				sm->skinID.push_back(val);

			}

		}
		//////////////////////////Attribute array creation/////////////////////////////////////
		for( PInt sID = 0; sID < sm->skinID.size() ; ++sID )
		{//for every vertex

				Syp::VertexWeightSet& vw = sm->VWeights[ sm->skinID[ sID ] ];
				size_t counter = 0;
				//Pack BoneIDs in 4s
				while( counter < vw.BoneID.size() )
				{
					sm->attribDatapb.push_back( static_cast<PByte>(vw.BoneID[ counter ]) );//BoneIDs
					++counter;
				}
				while( counter < 4 )//4 is the number of hardware bones supported per vertex
				{

					sm->attribDatapb.push_back( 0 );//BoneID
					++counter;
				}

				counter = 0;
				//Pack weights in 4s
				assert(vw.weight.size() <= 4 && "Model has vertices influenced by more than 4 weights. Please edit model and try again.");
				while( counter < vw.weight.size() )
				{
					sm->attribData.push_back(  vw.weight[ counter ] );//BoneIDs
					++counter;
				}
				while( counter < 4 )//4 is the number of hardware bones supported per vertex
				{

					sm->attribData.push_back( 0 );//weight
					++counter;
				}


		}


		////DEBUG
		//for(PInt wtf=0;wtf<sm->index.size();++wtf)
		//	std::cout<<sm->index[wtf]<<" ";

		//	std::cout<<"\n";

		////DEBUG
		//for(PInt wtf=0;wtf<sm->data.size();++wtf)
		//	std::cout<<sm->data[wtf]<<" ";

		//std::cout<<"\n";

		fin.close();
		if(autoUpdateMesh)
		{
			Renderer::getRenderer().updateMesh(sm);
			Renderer::getRenderer().updateIndices(sm);
		}
		return sm;
	}

	FloatArray& IndexedMesh::getAttribDataRef()
	{
		return attribData;
	}

	PByteArray& IndexedMesh::getAttribDatapbRef()
	{
		return attribDatapb;
	}
	//IndexedMesh* IndexedMesh::loadFromFile(const String& fileName,bool autoUpdateMesh)
	//{
	//	IndexedMesh* bm = static_cast<IndexedMesh*>(ResourceManager::getResourceManager().isResourceLoaded(fileName));
	//	if(bm)
	//	{
	//		return bm;
	//	}


	//	IndexedMesh* sm = new IndexedMesh(fileName,DYNAMIC);
	//	InputStream fin;
	//	fin.open(fileName.c_str());
	//	String temp;
	//	PInt tNum = 0;
	//	PShort tShort;
	//	float tFloat;
	//	bool hasUV;


	//	//Example:
	//	//Material 01 - Default.mat
	//	//Textures N Vertices 24 Index 2

	//	fin>>temp;
	//	fin>>temp;
	//	sm->setDefaultMaterial(temp);


	//	fin>>temp;
	//	fin>>temp;
	//	if(temp == "Y")
	//	{//Store it here temporarily
	//		hasUV = true;
	//	}
	//	else
	//	{
	//		hasUV = false;
	//	}
	//	fin>>temp;
	//	if(temp == "Vertices")
	//	{
	//		fin>>sm->numOfVertices;
	//	}
	//	else
	//	{
	//		ErrorLogger::showError("Vertices header not found in file");
	//		ErrorLogger::showError(fileName);
	//	}
	//	fin>>temp;
	//	PInt numOfMaterials;
	//	if(temp == "DrawCalls")
	//	{
	//		fin>>numOfMaterials;
	//		//allocate memory for indices
	//		//TODO: Change exporter to export total num of indices so that loader may reserve memory for it.
	//	}
	//	else
	//	{
	//		ErrorLogger::showError("DrawCalls header not found in file");
	//		ErrorLogger::showError(fileName);
	//	}

	//	fin>>temp;
	//	if(temp == "Indices")
	//	{
	//		fin>>tNum;
	//		//allocate memory for indices
	//		//TODO: Change exporter to export total num of indices so that loader may reserve memory for it.
	//		sm->index.reserve(tNum);
	//	}
	//	else
	//	{
	//		ErrorLogger::showError("DrawCalls header not found in file");
	//		ErrorLogger::showError(fileName);
	//	}


	//	int floatsPerVertex;
	//	//If no texture
	//	if(!hasUV)
	//	{
	//		//3 vertices followed by 3 normals
	//		floatsPerVertex = 6;
	//		sm->vertType = VN;
	//	}
	//	else
	//	{
	//		//3 vertices followed by 3 normals followed by 2 UV coordinates
	//		floatsPerVertex = 8;
	//		sm->vertType = VNT;
	//	}
	//	//allocate memory 1st as it is more efficient
	//	sm->data.reserve(floatsPerVertex * sm->numOfVertices);
	//	//read in vertices
	//	for(PInt i=0;i < sm->numOfVertices;++i)
	//	{
	//		for(int j=0;j < floatsPerVertex;++j)
	//		{
	//			fin>>tFloat;
	//			sm->data.push_back(tFloat);
	//		}
	//	}
	//	//Now read in the indices
	//	for(PInt k=0;k < numOfMaterials;++k)
	//	{
	//		IndexBlock ib;

	//		fin>>temp;
	//		fin>>ib.materialID;

	//		fin>>temp;
	//		fin>>ib.smallest;

	//		fin>>temp;
	//		fin>>ib.largest;

	//		fin>>temp;
	//		fin>>ib.count;

	//		fin>>temp;
	//		fin>>ib.offset;

	//		for(PInt huh=0;huh<ib.count;++huh)
	//		{
	//			fin>>tShort;
	//			sm->index.push_back(tShort);
	//		}
	//		sm->drawCalls.push_back(ib);
	//	}

	//	//Read in for skin/noskin
	//	fin>>temp;
	//	if(temp == "Skin")
	//	{
	//		//Since it has a skin, we assume there will be animation.
	//		//We start by making a backup of the original mesh data/vertices.
	//		//Allocate enough memory
	//		sm->bakData.resize( sm->data.size() );
	//		//Copy it
	//		std::copy( sm->data.begin(),sm->data.end(),sm->bakData.begin() );

	//		////REMOVE
	//		//std::vector<float>::iterator p = sm->bakData.begin();
	//		//while(p != sm->bakData.end())
	//		//{
	//		//	ErrorLogger::getLogger()<<*p<<" "<<std::endl;
	//		//	++p;
	//		//}
	//		////REMOVE

	//		//has skin, likely to be dynamic
	//		sm->type = DYNAMIC;
	//		sm->hasSkin = true;

	//		PShort tIndex;
	//		//Read in VWeight indices
	//		for(PInt i=0;i<sm->numOfVertices;++i)
	//		{
	//			fin>>tIndex;
	//			sm->skinID.push_back(tIndex);
	//		}
	//		fin>>temp;


	//		//read in the VWeights
	//		if(temp=="NumOfVWeights")
	//		{
	//			PInt numVWeights = 0;
	//			PInt numVert = 0;

	//			PShort tBoneID;
	//			float tWeight;
	//			//read in number of VWeight sets
	//			fin>>numVWeights;
	//			//for every set
	//			for(PInt i=0;i<numVWeights;++i)
	//			{
	//				//Make a VertexWeightSet
	//				VertexWeightSet vset;
	//				//read in number of weights for this set
	//				fin>>numVert;
	//				for(PInt j=0;j<numVert;++j)
	//				{
	//					//read in BoneID
	//					fin>>tBoneID;
	//					fin>>tWeight;

	//					//push in the BoneID/Weight
	//					vset.BoneID.push_back(tBoneID);
	//					vset.weight.push_back(tWeight);
	//				}
	//				//push back the vWeight
	//				sm->VWeights.push_back(vset);

	//			}

	//			//This var keeps track of the longest animated bone time in sec. The longest time is the animation length of this mesh.
	//			float AnimLength = 0.0f;

	//			//Read in Bones
	//			fin>>temp;
	//			if(temp=="NumOfBones")
	//			{
	//				fin>>tShort;
	//				sm->Bones.reserve(tShort);
	//				//temporary bone
	//				Bone bn;
	//				PInt currBone = 0;

	//				for(int b=0;b<tShort;++b)
	//				{

	//					fin>>temp;//read in Name
	//					fin>>bn.name;
	//					fin>>temp;//read in ID
	//					fin>>bn.ID;

	//					//skip initial postion line for now
	//					fin>>temp; //read in initialposition
	//					fin>>bn.pos.x;
	//					fin>>bn.pos.y;
	//					fin>>bn.pos.z;

	//					fin>>temp;
	//					fin>>bn.rot.x;
	//					fin>>bn.rot.y;
	//					fin>>bn.rot.z;
	//					fin>>bn.rot.w;



	//					sm->Bones.push_back(bn);

	//				}
	//				//Read in Hierarchy
	//				fin>>temp;//read in Bone for 1st Bone link
	//				while(temp != "EndHierarchy")
	//				{
	//					fin>>temp;//The Bone in question
	//					Bone& b = sm->getBoneRef(temp);
	//					fin>>temp;//Read in Parent
	//					fin>>temp;//Read in Parents name
	//					Bone& p = sm->getBoneRef(temp);
	//					b.Parent = p.ID;
	//					b.ParentPtr = &p;

	//					//ErrorLogger::getLogger()<<"Bone "<<b.ID<<"Parent "<<b.Parent<<std::endl;

	//					fin>>temp;//read in Bone
	//				}


	//				//Temporary keyFrame
	//				KeyFrame keyF;

	//				fin>>temp;//read in AnimationBone

	//				for(int b=0;b<tShort;++b)
	//				{

	//					fin>>temp;
	//					//find the bone ID from name
	//					currBone = sm->getBoneID(temp);

	//					fin>>temp;//read in Time

	//					while(temp == "Time")
	//					{
	//						//read in time value
	//						fin>>keyF.time;
	//						//4800 ticks is 1 sec
	//						keyF.time /= 4800.0f;
	//						//read in Pos
	//						fin>>temp;

	//						fin>>keyF.Pos.x;
	//						fin>>keyF.Pos.y;
	//						fin>>keyF.Pos.z;


	//						//Read in Rot
	//						fin>>temp;
	//						fin>>keyF.Rot.x;
	//						fin>>keyF.Rot.y;
	//						fin>>keyF.Rot.z;
	//						fin>>keyF.Rot.w;

	//						//Copy the keyframe over into the bone
	//						sm->Bones[ b ].KFrame.push_back(keyF);
	//						//read in time again
	//						fin>>temp;

	//					}
	//					//No more animations
	//					//Check if this is longest animated bone
	//					if(keyF.time > AnimLength)
	//					{
	//						AnimLength = keyF.time;
	//					}

	//				}
	//				//Store max length of animation
	//				sm->AnimLength = AnimLength;

	//			}
	//			else
	//			{
	//				ErrorLogger::showError("NumOfBones header not found in file");
	//				ErrorLogger::showError(fileName);
	//			}
	//		}
	//		else
	//		{
	//			ErrorLogger::showError("NumOfVWeights header not found in skinnedmesh");
	//			ErrorLogger::showError(fileName);

	//		}


	//	}
	//	else
	//	{//no skin
	//		sm->type = STATIC;
	//	}




	//	fin.close();

	//	std::vector<Bone>::iterator BBegin = sm->Bones.begin();
	//	std::vector<Bone>::iterator BEnd = sm->Bones.end();

	//	while(BBegin != BEnd)
	//	{
	//		calcBoneInverse(*BBegin);
	//		++BBegin;
	//	}
	//	//Analyzes all IDs, and gives them new ids so that boneIDs can be used for random access and increase efficiency.
	//	std::vector<VertexWeightSet>::iterator beg = sm->VWeights.begin();
	//	std::vector<VertexWeightSet>::iterator en = sm->VWeights.end();

	//	ShortArray oldID;
	//	//reassign their own IDs
	//	for(PInt bID = 0; bID < sm->Bones.size(); ++bID)
	//	{
	//		oldID.push_back( sm->Bones[bID].ID );
	//		//assign new ID
	//		sm->Bones[bID].ID = bID;
	//	}
	//	//Reassign their new parent IDs
	//	for(PInt bID = 0; bID < sm->Bones.size(); ++bID)
	//	{
	//		if(sm->Bones[bID].Parent != -1)
	//		{
	//			sm->Bones[bID].Parent = sm->Bones[bID].ParentPtr->ID;
	//		}
	//	}

	//	//for every VWeight's contents
	//	while(beg != en)
	//	{
	//		//Go thru all the VWeights affected bones
	//		for(PInt ih=0; ih < beg->BoneID.size(); ++ih)
	//		{
	//			PInt count = 0;
	//			//For each bone, find the ID in the old list
	//			while(beg->BoneID[ih] != oldID[count])
	//			{
	//				++count;
	//			}

	//			//fix the BoneID by assigning the index value counted by count
	//			beg->BoneID[ih] = count;

	//		}
	//		++beg;

	//	}
	//	if(autoUpdateMesh)
	//	{
	//		Renderer::getRenderer().updateMesh(sm);
	//		Renderer::getRenderer().updateIndices(sm);
	//	}

	//	return sm;
	//}



}
